package org.dallasrowing.logbook.ui.controller;

import java.util.List;

import org.dallasrowing.logbook.ui.view.BeanEditorWidget;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Test;

public abstract class BeanEditorControllerTestBase<T> {

	protected Mockery context = new JUnit4Mockery();
	protected BeanEditorControllerImpl<T> controller;

	protected BeanEditorWidget<T> beanWidget;
	protected AdminWindowController parentController;
	
	@SuppressWarnings("unchecked")
	public void setUp() throws Exception
	{
		beanWidget = context.mock(BeanEditorWidget.class);
		parentController = context.mock(AdminWindowController.class);

		expectLoadBeansInternal();

		expectRegisterListeners();
	}

	private void expectLoadBeansInternal() throws Exception {
		final List<T> beanList = expectLoadBeans();
		context.checking(new Expectations(){{
			one(beanWidget).fillBeans(beanList);
		}});
	}
	
	protected abstract List<T> expectLoadBeans() throws Exception;

	protected abstract void expectUpdatesBeanInDB() throws Exception;
	
	protected abstract void expectCreateBeanInDB() throws Exception;

	@Test
	public void beanSelected_UpdatesBeanFields() throws Exception
	{
		expectReadSelectedIndex();
		expectUpdatesWidgetFields();
		expectEnableUpdate();
		
		controller.beanSelected();
	}
	
	@Test
	public void updateClicked_UpdatesBeanInDb() throws Exception
	{
		expectReadSelectedIndex();
		expectReadsWidgetFields();
		expectUpdatesBeanInDB();
		expectClose();
		
		controller.updateClicked();
	}
	
	@Test
	public void createNewBean_CreateNewBeanInDB() throws Exception
	{
		expectReadsWidgetFields();
		expectCreateBeanInDB();
		expectClose();
		
		controller.createNewBean();
	}
	
	@Test
	public void createNewClicked_EmptiesFieldsAndCreatesNew() throws Exception
	{
		expectEnableCreateNew();

		controller.createNewClicked();
	}

	private void expectRegisterListeners() throws Exception {
		context.checking(new Expectations(){{
			one(beanWidget).onBeanSelected(with(any(Runnable.class)));
			one(beanWidget).onCloseClicked(with(any(Runnable.class)));
			one(beanWidget).onUpdateClicked(with(any(Runnable.class)));
			one(beanWidget).onCreateNewClicked(with(any(Runnable.class)));
		}});
	}

	private void expectEnableUpdate() {
		context.checking(new Expectations(){{
			one(beanWidget).enableUpdate();
		}});
	}

	private void expectEnableCreateNew() {
		context.checking(new Expectations(){{
			one(beanWidget).enableNew();
		}});
	}

	private void expectClose() {
		context.checking(new Expectations(){{
			one(parentController).close();
		}});
	}


	private void expectReadSelectedIndex() {
		context.checking(new Expectations(){{
			one(beanWidget).getSelectedBean();
			will(returnValue(1));
		}});
	}

	@SuppressWarnings("unchecked")
	private void expectReadsWidgetFields() {
		context.checking(new Expectations(){{
			one(beanWidget).updateBean((T) with(any(Object.class)));
		}});
		
	}

	@SuppressWarnings("unchecked")
	private void expectUpdatesWidgetFields() {
		context.checking(new Expectations(){{
			one(beanWidget).setBean((T) with(any(Object.class)));
		}});
	}

}
